﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace demoReflection
{
    public class AutoGenerateAssembly
    {
        
        private AssemblyName _assemblyName;
        private AssemblyBuilder _assemblyBuilder;
        private List<AutoGenerateType> _customTypes;
        private List<TypeBuilder> _typebuilders;
        private ModuleBuilder _moduleBuilder;
        public AutoGenerateAssembly(string assemblyName, string storeDirectory="")
        {
            if (string.IsNullOrWhiteSpace(storeDirectory))
                storeDirectory = AppDomain.CurrentDomain.BaseDirectory;
            _assemblyName = new AssemblyName(assemblyName);
            _assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.RunAndSave, storeDirectory);
            _customTypes = new List<AutoGenerateType>();
        }

        public void AddType(AutoGenerateType customType)
        {
            customType.ModuleName = _assemblyName.Name;
            _customTypes.Add(customType);
        }
        public void AddType(List<AutoGenerateType> moduleList)
        {
            for (int i = 0; i < moduleList.Count; i++)
            {
                AddType(moduleList[i]);
            }
        }

        public void AddType(string moduleName, List<CustomFieldInfo> properties)
        {
            AutoGenerateType module = new AutoGenerateType(moduleName, properties);
            AddType(module);
        }


        public void BuildAssembly()
        {
            _moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyName.Name + ".dll");

            // define typebuilders
            _typebuilders = new List<TypeBuilder>();
            for (int i = 0; i < _customTypes.Count; i++)
            {
                TypeBuilder tb = _moduleBuilder.DefineType(_customTypes[i].Name, TypeAttributes.Public);
                _typebuilders.Add(tb);
            }

            // build types
            for (int i = 0; i < _customTypes.Count; i++)
            {
                TypeBuilder tb = _typebuilders[i];
                _customTypes[i].Build(_assemblyName.Name, _typebuilders[i], _typebuilders);
            }

            // create types
            for (int i = 0; i < _typebuilders.Count; i++)
            {
                _typebuilders[i].CreateType();
            }

        }
        public void SaveAssembly()
        {
            _assemblyBuilder.Save(_assemblyName.Name +".dll");
        }
    }
}


